﻿#------------------------------------------------------------------------------
# Name:        module1
# Purpose:
#
# Author:      Hu Jun
#
# Created:     28/07/2011
# Copyright:   (c) Hu Jun 2011
# Licence:     Apache 2
#------------------------------------------------------------------------------
#!/usr/bin/env python
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO
import time
import mimetypes
import SocketServer
import posixpath
import BaseHTTPServer
import threading
import urllib
import urlparse
import os.path
import glob
from datetime import datetime
import shutil
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
import DTIEP
import struct
GlobalConfig={}
GlobalConfig['ServerPort']=8080
GlobalConfig['password']="DtIE%6&~"


class DTHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):


    """Simple HTTP request handler with GET and HEAD commands.

    This serves files from the current directory and any of its
    subdirectories.  The MIME type for files is determined by
    calling the .guess_type() method.

    The GET and HEAD requests are identical except that the HEAD
    request omits the actual contents of the file.

    """
    __version__ = "0.1"
    __all__ = ["DTHTTPRequestHandler"]
    server_version = "SimpleHTTP/" +__version__

    def log_request(self,code=1,size=0):
        pass

    def log_error(self,*args, **kwds):
        pass

    def setup(self):
        global GlobalConfig
        BaseHTTPServer.BaseHTTPRequestHandler.setup(self)
        self.RList=None
        m=hashlib.md5()
        m.update(GlobalConfig['password'])
        m.update(m.digest())
        self.mykey=m.digest()



    def setRList(self,list):
        self.RList=list


    def do_GET(self):
        """Common code for GET and HEAD commands.

        This sends the response code and MIME headers.

        Return value is either a file object (which has to be copied
        to the outputfile by the caller unless the command was HEAD,
        and must be closed by the caller under all circumstances), or
        None, in which case the caller has nothing further to do.

        """
##        print "get request for:",self.path
        path = self.translate_path(self.path)
##        print path
##        if path == False or self.RList==None or \
##                not path['target'] in self.RList:
##            self.send_error(404,"File not found")
##            return None
        f = None
        if path == False:
            self.send_error(404,"File not found")
            return None
        path=path['target'][0]
        ctype = self.guess_type(path)
        if path=="___text" or path=='___img' or path==___filelist:
            if GlobalConfig['CurrentResource']==None or \
                GlobalConfig['CurrentResource']==""  or \
                not GlobalConfig.has_key('CurrentResource'):
                    self.send_error(404,"File not found")
                    return None
            f=StringIO(GlobalConfig['CurrentResource'])
        else:
            try:
                # Always read in binary mode. Opening files in text mode may cause
                # newline translations, making the actual size of the content
                # transmitted *less* than the content-length!
                f = open(path, 'rb')
            except IOError:
                self.send_error(404,"File not found")
                return None
        self.send_response(200)
        self.send_header("Content-type", ctype)
        IV=Random.get_random_bytes(16)
        o=AES.new(self.mykey,AES.MODE_CBC,IV)
        ctxt=f.read()
        cipher=o.encrypt(DTIEP.strpad(ctxt))
        fmt_str='16sQ'
        hder=struct.pack(fmt_str,IV,len(ctxt))
        rtxt=hder+cipher
        fs = len(rtxt)
##        print "fs is",fs


        self.send_header("Content-Length", str(fs))
        if path=="___text" or path=='___img':
            self.send_header("Last-Modified", self.date_time_string(time.time()))
        else:
            self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
        self.end_headers()
        self.wfile.write(rtxt)
        f.close()
        return f



    def translate_path(self, path):
        """Translate a /-separated PATH to a dict:
            'target': url of target resouce
            'IV': IV for encryption (optional)
        """
        path=path[1:]
        qd=urlparse.parse_qs(path)
##        print "qd is ",qd
        if not "target" in qd.keys():
            return False
        for k,v in qd.iteritems():
            v[0]=v[0].decode('utf')
            qd[k]=v
        return qd

    def guess_type(self, path):
        """return mime type for DTIE
        """
        return 'application/dtie'

class ThreadedDTServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass

def main():
    global GlobalConfig
    #starting web server
    GlobalConfig['CurrentResource']="xdddddixixhaha"
    GlobalConfig['password']="xixixhaha"
    server = ThreadedDTServer(('', GlobalConfig['ServerPort']), DTHTTPRequestHandler)
    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.setDaemon(True)
    server_thread.start()
    while True:
        pass
if __name__ == '__main__':
    main()
